#pragma once

// base classes
#include "API/TESForms/TESForm.h" // TESFormIDListView
#include "API/TESForms/BaseFormComponent.h" // additonal form components
#include "Components/ExtendedForm.h"

#include "NiTOrphanList.h"

class BSStringT;
class TESObjectARMO;
class TESObjectCLOT;
class TESObjectWEAP;
class TESBipedModelForm;

struct AffixList;

// Macros for short name and class name, which must be unique among all plugins, and just this plugin, respectively
#define AFFIXFILTER_SHORTNAME "ARAF"
#define AFFIXFILTER_CLASSNAME "AffixFilter"

class MagicItemGenerator;
#ifndef OBLIVION
	class CAffixFilterDlg;
#endif

typedef UInt8 tri; // 0: false, 1: true, 2: indeterminate

class AffixFilter : public TESForm {
public:
	class Affixes { // basically "faking" std::pair<MagicItemGenerator*,UInt8> in order to include operator=()
	public:
		MagicItemGenerator* first;
		UInt8 second;
		Affixes(MagicItemGenerator* mig = NULL, UInt8 souls = 0) : first(mig), second(souls) { }
		Affixes(const int i) : first(NULL), second(0) { }
		Affixes(const Affixes& copied) : first(copied.first), second(copied.second) { }
		~Affixes() { }
		Affixes& operator=(const Affixes& copied) {
			first = copied.first;
			second = copied.second;
		}
		Affixes& operator=(const int i) { first = NULL; second = 0; }
		bool operator==(const Affixes& right) const { return first == right.first && second == right.second; }
		bool operator!=(const Affixes& right) const { return first != right.first || second != right.second; }

		struct AffixesSaveData {
			UInt32 formID;
			UInt8 souls;
		};
	};

	// common to all types
	MEMBER NiTOrphanList<Affixes>	migs;
	MEMBER BSStringT			nameFilter;

	MEMBER SInt32				minVal;
	MEMBER SInt32				maxVal;
	MEMBER float				minWht;
	MEMBER float				maxWht;
	MEMBER bool					app;
	MEMBER bool					arm;
	MEMBER bool					wep;

	MEMBER UInt8				app_types;
	enum ApparelType {
		kTypeApp_Cloth		= 1/*<<0*/,
		kTypeApp_Light		= 1 << 1,
		kTypeApp_Heavy		= 1 << 2,
		kTypeApp_ALL		=(1 << 3) - 1
	};

	MEMBER UInt8				wep_types;
	enum WeaponType {
		kTypeWep_Blade1h	= 1/*<<0*/,
		kTypeWep_Blade2h	= 1 << 1,
		kTypeWep_Blunt1h	= 1 << 2,
		kTypeWep_Blunt2h	= 1 << 3,
		kTypeWep_Bow		= 1 << 4,
		kTypeWep_Staff		= 1 << 5,
		kTypeWep_ALL		=(1 << 6) - 1
	};

	// common to both armor and weapons
	MEMBER UInt32				minDur;
	MEMBER UInt32				maxDur;

	// common to apparel
	MEMBER UInt8				minAR;
	MEMBER SInt16				maxAR;
	MEMBER tri					hidesRings;
	MEMBER tri					hidesAmulet;
	MEMBER tri					head;
	MEMBER tri					hair;
	MEMBER tri					bodyUp;
	MEMBER tri					bodyLo;
	MEMBER tri					hand;
	MEMBER tri					foot;
	MEMBER tri					ringR;
	MEMBER tri					ringL;
	MEMBER tri					amulet;
	MEMBER tri					weapon;
	MEMBER tri					weaponBack;
	MEMBER tri					weaponSide;
	MEMBER tri					quiver;
	MEMBER tri					shield;
	MEMBER tri					torch;
	MEMBER tri					tail;
	MEMBER BSStringT			bipedMaleFilter;
	MEMBER BSStringT			bipedFemaleFilter;
	MEMBER BSStringT			groundMaleFilter;
	MEMBER BSStringT			groundFemaleFilter;
	MEMBER BSStringT			iconMaleFilter;
	MEMBER BSStringT			iconFemaleFilter;

	// common to weapons
	MEMBER UInt16				minDmg;
	MEMBER UInt16				maxDmg;
	MEMBER UInt8				minRng;
	MEMBER SInt16				maxRng;
	MEMBER UInt8				minSpd;
	MEMBER SInt16				maxSpd;
	MEMBER tri					ignoresNWRes;
	MEMBER BSStringT			weaponFilter;
	MEMBER BSStringT			iconWeaponFilter;

	MEMBER UInt16				numMask;
	enum numFields {
		kNum_MinVal	= 1 << 0,
		kNum_MaxVal = 1 << 1,
		kNum_MinWht = 1 << 2,
		kNum_MaxWht = 1 << 3,
		kNum_MinDur = 1 << 4,
		kNum_MaxDur = 1 << 5,
		kNum_MinAR	= 1 << 6,
		kNum_MaxAR	= 1 << 7,
		kNum_MinDmg	= 1 << 8,
		kNum_MaxDmg	= 1 << 9,
		kNum_MinRng	= 1 << 10,
		kNum_MaxRng	= 1 << 11,
		kNum_MinSpd	= 1 << 12,
		kNum_MaxSpd	= 1 << 13
	};

	MEMBER NiTOrphanList<BSStringT>	rareFirsts;
	MEMBER NiTOrphanList<BSStringT>	rareSeconds;
	
	_LOCAL virtual				~AffixFilter();
	_LOCAL virtual bool			LoadForm(TESFile& file);
	_LOCAL virtual void			SaveFormChunks();
	_LOCAL virtual UInt8		GetFormType();
	_LOCAL virtual void			CopyFrom(TESForm& form);
	_LOCAL virtual bool			CompareTo(TESForm& compareTo);
#ifndef OBLIVION
	_LOCAL virtual void			SetInDialog(HWND dialog);
	_LOCAL virtual void			GetFromDialog(HWND dialog);
#endif

	// constructor
	_LOCAL AffixFilter();
	_LOCAL AffixFilter(const AffixFilter& copied);
    
	// COEF ExtendedForm component
	static ExtendedForm         extendedForm;
	_LOCAL static TESForm*      CreateAffixFilter(); // creates a blank AffixFilter

	MEMBER static tri			intToCheck(const int& n);
	MEMBER static int			checkToInt(const tri& n);
	
	MEMBER UInt32				GetNumAffixes() const;
	MEMBER bool					AddAffix(MagicItemGenerator* new_mig, UInt8 new_soul);
	MEMBER bool					DeleteNthAffix(UInt32 n);

	MEMBER UInt32				GetNthAffixMagicItemGenerator(UInt32 n) const;
	MEMBER bool					SetNthAffixMagicItemGenerator(UInt32 n, MagicItemGenerator* new_mig);
	MEMBER UInt8				GetNthAffixMask(UInt32 n) const;
	MEMBER bool					SetNthAffixMask(UInt32 n, UInt8 new_soul);

	MEMBER BSStringT			GetNameFilter() const;
	MEMBER bool					SetNameFilter(const BSStringT& new_name);
	MEMBER double				GetMinValue() const;
	MEMBER bool					SetMinValue(double new_min_val);
	MEMBER double				GetMaxValue() const;
	MEMBER bool					SetMaxValue(double new_max_val);
	MEMBER bool					CheckValue(double value) const;
	MEMBER double				GetMinWeight() const;
	MEMBER bool					SetMinWeight(double new_min_wht);
	MEMBER double				GetMaxWeight() const;
	MEMBER bool					SetMaxWeight(double new_max_wht);
	MEMBER bool					CheckWeight(double weight) const;
	MEMBER double				GetMinDurability() const;
	MEMBER bool					SetMinDurability(double new_min_dur);
	MEMBER double				GetMaxDurability() const;
	MEMBER bool					SetMaxDurability(double new_max_dur);
	MEMBER bool					CheckDurability(double durability) const;

	MEMBER UInt8				GetApparelMask() const;
	MEMBER bool					SetApparelMask(UInt8 new_mask);
	MEMBER double				GetMinArmorRating() const;
	MEMBER bool					SetMinArmorRating(double new_min_AR);
	MEMBER double				GetMaxArmorRating() const;
	MEMBER bool					SetMaxArmorRating(double new_max_AR);
	MEMBER bool					CheckArmorRating(double AR) const;
	MEMBER tri					GetHidesRings() const;
	MEMBER bool					SetHidesRings(tri new_check);
	MEMBER tri					GetHidesAmulet() const;
	MEMBER bool					SetHidesAmulet(tri new_check);
	MEMBER tri					GetBipedHead() const;
	MEMBER bool					SetBipedHead(tri new_check);
	MEMBER tri					GetBipedHair() const;
	MEMBER bool					SetBipedHair(tri new_check);
	MEMBER tri					GetBipedBodyLower() const;
	MEMBER bool					SetBipedBodyLower(tri new_check);
	MEMBER tri					GetBipedBodyUpper() const;
	MEMBER bool					SetBipedBodyUpper(tri new_check);
	MEMBER tri					GetBipedHand() const;
	MEMBER bool					SetBipedHand(tri new_check);
	MEMBER tri					GetBipedFoot() const;
	MEMBER bool					SetBipedFoot(tri new_check);
	MEMBER tri					GetBipedRingLeft() const;
	MEMBER bool					SetBipedRingLeft(tri new_check);
	MEMBER tri					GetBipedRingRight() const;
	MEMBER bool					SetBipedRingRight(tri new_check);
	MEMBER tri					GetBipedAmulet() const;
	MEMBER bool					SetBipedAmulet(tri new_check);
	MEMBER tri					GetBipedWeapon() const;
	MEMBER bool					SetBipedWeapon(tri new_check);
	MEMBER tri					GetBipedWeaponBack() const;
	MEMBER bool					SetBipedWeaponBack(tri new_check);
	MEMBER tri					GetBipedWeaponSide() const;
	MEMBER bool					SetBipedWeaponSide(tri new_check);
	MEMBER tri					GetBipedQuiver() const;
	MEMBER bool					SetBipedQuiver(tri new_check);
	MEMBER tri					GetBipedShield() const;
	MEMBER bool					SetBipedShield(tri new_check);
	MEMBER tri					GetBipedTorch() const;
	MEMBER bool					SetBipedTorch(tri new_check);
	MEMBER tri					GetBipedTail() const;
	MEMBER bool					SetBipedTail(tri new_check);
	MEMBER BSStringT			GetModelFilterBipedMale() const;
	MEMBER bool					SetModelFilterBipedMale(const BSStringT& new_name);
	MEMBER BSStringT			GetModelFilterBipedFemale() const;
	MEMBER bool					SetModelFilterBipedFemale(const BSStringT& new_name);
	MEMBER BSStringT			GetModelFilterGroundMale() const;
	MEMBER bool					SetModelFilterGroundMale(const BSStringT& new_name);
	MEMBER BSStringT			GetModelFilterGroundFemale() const;
	MEMBER bool					SetModelFilterGroundFemale(const BSStringT& new_name);
	MEMBER BSStringT			GetIconFilterMale() const;
	MEMBER bool					SetIconFilterMale(const BSStringT& new_name);
	MEMBER BSStringT			GetIconFilterFemale() const;
	MEMBER bool					SetIconFilterFemale(const BSStringT& new_name);
	
	MEMBER UInt8				GetWeaponMask() const;
	MEMBER bool					SetWeaponMask(UInt8 new_mask);
	MEMBER double				GetMinDamage() const;
	MEMBER bool					SetMinDamage(double new_min_dmg);
	MEMBER double				GetMaxDamage() const;
	MEMBER bool					SetMaxDamage(double new_max_dmg);
	MEMBER bool					CheckDamage(double damage) const;
	MEMBER double				GetMinReach() const;
	MEMBER bool					SetMinReach(double new_min_rng);
	MEMBER double				GetMaxReach() const;
	MEMBER bool					SetMaxReach(double new_max_rng);
	MEMBER bool					CheckReach(double reach) const;
	MEMBER double				GetMinSpeed() const;
	MEMBER bool					SetMinSpeed(double new_min_spd);
	MEMBER double				GetMaxSpeed() const;
	MEMBER bool					SetMaxSpeed(double new_max_spd);
	MEMBER bool					CheckSpeed(double speed) const;
	MEMBER tri					GetIgnoresNormalWeaponResistance() const;
	MEMBER bool					SetIgnoresNormalWeaponResistance(tri new_check);
	MEMBER BSStringT			GetModelFilterWeapon() const;
	MEMBER bool					SetModelFilterWeapon(const BSStringT& new_name);
	MEMBER BSStringT			GetIconFilterWeapon() const;
	MEMBER bool					SetIconFilterWeapon(const BSStringT& new_name);
	
	MEMBER UInt8				GetNumRareFirstNames() const;
	MEMBER bool					AddRareFirstName(const BSStringT& newName);
	MEMBER BSStringT			GetNthRareFirstName(UInt8 i) const;
	MEMBER bool					DeleteNthRareFirstName(UInt8 i);

	MEMBER UInt8				GetNumRareSecondNames() const;
	MEMBER bool					AddRareSecondName(const BSStringT& newName);
	MEMBER BSStringT			GetNthRareSecondName(UInt8 i) const;
	MEMBER bool					DeleteNthRareSecondName(UInt8 i);

	MEMBER bool					Check(const TESObjectARMO* armor) const;
	MEMBER bool					Check(const TESObjectCLOT* clothing) const;
	MEMBER bool					CheckApparel(const TESBipedModelForm* apparel) const;
	MEMBER bool					Check(const TESObjectWEAP* weapon) const;

	MEMBER bool					SortAffixes(AffixList& prefixes, AffixList& suffixes, UInt16 level, bool LtEq = true) const;

#ifndef OBLIVION
	static bool					mod;
	static AffixFilter*			currPtr;
	static CAffixFilterDlg*		fltDlg;
	static UInt32               kMenuIdentifier;   // identifier for new menu item
	static HWND                 dialogHandle; // handle of dialog if currently open
	static void					OpenDialog(); // opens dialog if it is not currently open
#endif

	// global initialization function, called once when submodule is first loaded
	_LOCAL static void          InitializeAffixFilter();
};
